﻿using lights;
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEngine;
using static UnityEngine.Networking.UnityWebRequest;

public class fptest : MonoBehaviour
{
    // Start is called before the first frame update
    SharedStatic<CommonDotsData> commonDots;
    void Start()
    {
        commonDots = SharedStatic<CommonDotsData>.GetOrCreate<CommonDotsData>();
        fp32v3.Init(ref commonDots.Data.tablecache);
    }

    // Update is called once per frame
    void Update()
    {

    }
    List<string> list = new List<string>();
    private void OnGUI()
    {
        GUILayout.Label("fixpoint test", GUILayout.Width(250));
        GUILayout.BeginVertical(GUILayout.Width(100));
        {

            DoTest();
        }
        GUILayout.EndVertical();
        foreach (var l in list)
        {
            GUILayout.Label(l);
        }
    }
    void TestLog(string msg)
    {
        list.Add(msg);
    }
    void DoTest()
    {
        if (GUILayout.Button("Test FP32 sin"))
        {
            list.Clear();
            fp32 a30 = fp32.PI2 * fp32.FromInt(30) / fp32.FromInt(360);//30度转弧度
            var sin = fp32.Sin(a30);
            var sin2 = fp32.SinFast(a30);
            var sin3 = fp32.SinFast2(a30);
            TestLog("v= " + a30 + " sin=" + sin + "," + sin2 + "," + sin3);
        }
        if (GUILayout.Button("Test FP32 Floor"))
        {
            list.Clear();
            float v1 = 4.434f;
            fp32 v = fp32.FromFloat(v1);
            TestLog("v=" + v);
            fp32 v2 = fp32.Floor(v);
            int vint = v.ToInt();
            TestLog("floor=" + v2);
            TestLog("toint=" + vint);
        }
        if (GUILayout.Button("Test FP32 acos"))
        {
            list.Clear();
            TestLog("test acos");
            for (var i = 0; i < 12; i++)
            {
                fp32 a30 = fp32.PI2 * fp32.FromInt(30 * i) / fp32.FromInt(360);//30度转弧度
                var cos = fp32.Cos(a30);
                TestLog("cos(" + a30 + ")=" + cos);
                var acos = fp32.Acos(cos);
                var acosf = fp32.AcosFast(cos);
                var acosf2 = fp32.AcosFast2(cos);
                TestLog("acos(" + cos + ")=" + acos + "," + acosf + "," + acosf2);
            }
        }
        if (GUILayout.Button("Test FP32 Sqrt(10M)"))
        {
            //测试开平方操作性能
            list.Clear();
            int count = 10000000;
            fp32 v = fp32.FromFloat(2);
            float vs = 2.0f;
            var t0 = DateTime.Now;
            for (var i = 0; i < count; i++)
            {
                var v2 = fp32.Sqrt(v);
            }
            var t1 = DateTime.Now;
            for (var i = 0; i < count; i++)
            {
                var v2 = fp32.SqrtFast(v);
            }
            var t2 = DateTime.Now;
            for (var i = 0; i < count; i++)
            {

                var v2 = fp32.SqrtFast2(v);
            }
            var t3 = DateTime.Now;
            for (var i = 0; i < count; i++)
            {

                var v2 = math.sqrt(vs);
            }
            var t4 = DateTime.Now;
            var basetime = (t4 - t3).TotalSeconds;
            var t1time = (t1 - t0).TotalSeconds;
            var t2time = (t2 - t1).TotalSeconds;
            var t3time = (t3 - t2).TotalSeconds;
            TestLog(" fp32.Sqrt v=" + v + " ->" + t1time + " Scale=X" + (t1time / basetime));
            TestLog(" fp32.SqrtFast v=" + v + " ->" + t2time + " Scale=X" + (t2time / basetime));
            TestLog(" fp32.SqrtFast2 v=" + v + " ->" + t3time + " Scale=X" + (t3time / basetime));
            TestLog(" math.sqrt v=" + v + " ->" + basetime);
        }
        if (GUILayout.Button("Test fp32v3 Length(1M)"))
        {
            //测试Length平方操作性能
            list.Clear();
            int count = 1000000;
            fp32v3 v3 = new fp32v3(fp32.FromFloat(0.001f), fp32.FromFloat(0.001f), fp32.FromFloat(0.001f));
            float3 f3 = v3.ToFloat3();
            var t0 = DateTime.Now;
            for (var i = 0; i < count; i++)
            {
                var v2 = fp32v3.LengthOld(v3);
            }
            var t1 = DateTime.Now;
            for (var i = 0; i < count; i++)
            {
                var v2 = fp32v3.Length(ref v3);
            }
            var t2 = DateTime.Now;
            for (var i = 0; i < count; i++)
            {
                var v2 = math.length(f3);
            }
            var t3 = DateTime.Now;


            var basetime = (t3 - t2).TotalSeconds;
            var t1time = (t1 - t0).TotalSeconds;
            var t2time = (t2 - t1).TotalSeconds;
            TestLog(" fp32.Length v=" + v3 + " ->" + t1time + " Scale=X" + (t1time / basetime));
            TestLog(" fp32.LengthRef v=" + v3 + " ->" + t2time + " Scale=X" + (t2time / basetime));
            TestLog(" math.length v=" + f3 + " ->" + basetime);
        }
        if (GUILayout.Button("Test fp32v3 Distance(1M)"))
        {
            //测试Length平方操作性能
            list.Clear();
            int count = 1000000;
            fp32v3 v3 = new fp32v3(fp32.FromFloat(0.001f), fp32.FromFloat(0.001f), fp32.FromFloat(0.001f));
            fp32v3 v32 = new fp32v3(fp32.FromFloat(0.31f), fp32.FromFloat(0.51f), fp32.FromFloat(0.101f));
            float3 f3 = v3.ToFloat3();
            float3 f32 = v32.ToFloat3();
            var t0 = DateTime.Now;
            for (var i = 0; i < count; i++)
            {
                var v2 = fp32v3.DistanceOld(v3,v32);
            }
            var t1 = DateTime.Now;
            for (var i = 0; i < count; i++)
            {
                var v2 = fp32v3.Distance(ref v3,ref v32);
            }
            var t2 = DateTime.Now;
            for (var i = 0; i < count; i++)
            {
                var v2 = math.length(f3-f32);
            }
            var t3 = DateTime.Now;


            var basetime = (t3 - t2).TotalSeconds;
            var t1time = (t1 - t0).TotalSeconds;
            var t2time = (t2 - t1).TotalSeconds;
            TestLog(" fp32.Length v=" + v3 + " ->" + t1time + " Scale=X" + (t1time / basetime));
            TestLog(" fp32.LengthRef v=" + v3 + " ->" + t2time + " Scale=X" + (t2time / basetime));
            TestLog(" math.length v=" + f3 + " ->" + basetime);
        }
        if (GUILayout.Button("Test fp32v3  calc angle(1M)"))
        {

            //测试Length平方操作性能
            list.Clear();
            int count = 1000000;
            fp32v3 dir1 = new fp32v3(fp32.FromInt(0), fp32.FromInt(3), fp32.FromInt(0));
            fp32v3 dir2 = new fp32v3(fp32.FromInt(0), fp32.FromInt(0), fp32.FromInt(1));

            float3 f1 = dir1.ToFloat3();
            float3 f2 = dir2.ToFloat3();
            var t0 = DateTime.Now;
            for (var i = 0; i < count; i++)
            {
                var v2 = fp32v3.CalcAngleOld(dir1, dir2);
            }
            var t1 = DateTime.Now;

            var t2 = DateTime.Now;
            for (var i = 0; i < count; i++)
            {
                var v2 = math.acos(math.dot(f1, f2));
            }
            var t3 = DateTime.Now;
            for (var i = 0; i < count; i++)
            {
                var v2 = fp32v3.CalcAngle(ref commonDots.Data.tablecache, ref dir1, ref dir2);
            }
            var t4 = DateTime.Now;

            var basetime = (t3 - t2).TotalSeconds;
            var t1time = (t1 - t0).TotalSeconds;
            var t2time = (t2 - t1).TotalSeconds;

            var t3time = (t4 - t3).TotalSeconds;
            TestLog(" fp32v3.Length v=" + dir1 + "," + dir2 + " ->" + t1time + " Scale=X" + (t1time / basetime));
            TestLog(" fp32v3.CalcAngle v=" + dir1 + "," + dir2 + " ->" + t2time + " Scale=X" + (t2time / basetime));
            TestLog(" math.acos(math.dot v=" + f1 + "," + f2 + " ->" + basetime);
            TestLog(" fp32v3.CalcAngleOP2 v=" + dir1 + "," + dir2 + " ->" + t3time + " Scale=X" + (t3time / basetime));
        }
        if (GUILayout.Button("Test fp32v3  calc angle 数据正确性验证"))
        {

            //测试Length平方操作性能
            list.Clear();
            var right = new Vector3(0, 0, 1);
            var rightv2 = fp32v3.FromFloat3(right);
            for (var i = 0; i < 30; i++)
            {
                var x = Mathf.Sin(Mathf.PI * 2 * i / 30);
                var z = Mathf.Cos(Mathf.PI * 2 * i / 30);
                var dir = new Vector3(x, 0, z);
                var dirv2 = fp32v3.FromFloat3(dir);

                var dot = Vector3.Dot(dir, right);
                var angle = Mathf.Acos(dot);

                var angle2 = fp32v3.CalcAngleOld(dirv2, rightv2);
                var angle4 = fp32v3.CalcAngle(ref commonDots.Data.tablecache, ref dirv2, ref rightv2);
                TestLog(" angle v1=" + angle + " v2=" + angle2 + " v4=" + angle4);
            }

        }
        if (GUILayout.Button("Test fp32v3  calc angle JobTest"))
        {

            MyJobSystem0 job0 = new MyJobSystem0();
            job0.fp32table = commonDots.Data.tablecache;
            JobHandle handle = job0.Schedule(100, 1);
            handle.Complete();
        }
        if (GUILayout.Button("Test lerp"))
        {
            list.Clear();
            TestLog("test angle");
            fp32v3 dir1 = new fp32v3(fp32.FromInt(0), fp32.FromInt(3), fp32.FromInt(0));
            fp32v3 dir2 = new fp32v3(fp32.FromInt(0), fp32.FromInt(0), fp32.FromInt(1));
            for (var i = 0; i <= 12; i++)
            {
                var w = fp32.FromInt(i) / fp32.FromInt(12);
                var v = fp32v3.Lerp(dir1, dir2, w);
                TestLog("v=" + v);
            }



        }
        if (GUILayout.Button("Test Cross"))
        {
            list.Clear();
            TestLog("test angle");
            fp32v3 dir1 = new fp32v3(fp32.FromInt(0), fp32.FromInt(3), fp32.FromInt(0));
            fp32v3 dir2 = new fp32v3(fp32.FromInt(0), fp32.FromInt(0), fp32.FromInt(1));
            var cross = fp32v3.Cross(fp32v3.NormalizeOld(dir1), fp32v3.NormalizeOld(dir2));
            TestLog("cross(" + dir1 + "," + dir2 + ")=" + cross);



        }
        if (GUILayout.Button("Test fp32_kd"))
        {
            list.Clear();
            TestLog("test fp32_kd");
            float v1 = 0.113f;
            var f = fp32.FromFloat(v1);//fp32虽然也会截尾巴，但是尾巴是 1/65536，数值不大，多半情况不用考虑
            var f2 = fp32_kd.FromFloat(v1 + 0.0005f);//千分位定点数,,float 转过来总会截尾巴。所以+1/2000 就相当于四舍五入了
            var f4 = fp32_kd.FromFp32(f + fp32.FromFloat(0.0005f));//从fp转过来也会截尾巴，所以也可以给fp32 + 1/2000 四舍五入
            TestLog("v from=" + v1 + " to=" + f + ",fromfloat=" + f2 + ",fromfp32=" + f4);

            TestLog("v=" + f.ToStringFix() + ",fromfloat=" + f2.ToStringFix() + ",fromfp32=" + f4.ToStringFix());

            var f5 = f4 + fp32_kd.FromFp32(f);
            TestLog("f5=" + f5);
            f5 += fp32_kd.FromFloat(0.01f + 0.0005f);//千分位定点数,,float 转过来总会截尾巴。所以+1/2000 就相当于四舍五入了
            TestLog("f5=" + f5);
        }
    }

    [BurstCompile]
    public struct MyJobSystem0 : IJobParallelFor
    {
        [ReadOnly]
        public fp32Table fp32table;
        public void Execute(int index)
        {
            var right = new Vector3(0, 0, 1);
            var rightv2 = fp32v3.FromFloat3(right);
            for (var j = 0; j < 100; j++)
                for (var i = 0; i < 30; i++)
                {
                    var x = Mathf.Sin(Mathf.PI * 2 * i / 30);
                    var z = Mathf.Cos(Mathf.PI * 2 * i / 30);
                    var dir = new Vector3(x, 0, z);
                    var dirv2 = fp32v3.FromFloat3(dir);

                    var dot = Vector3.Dot(dir, right);
                    var angle = Mathf.Acos(dot);

                    var angle2 = fp32v3.CalcAngleOld(dirv2, rightv2);
                    var angle4 = fp32v3.CalcAngle(ref fp32table, ref dirv2, ref rightv2);
                }

            Debug.LogWarning("jobjob.");
        }


    }
}
